package com.itheima.sfbx.file.web;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.itheima.sfbx.file.handler.aliyun.properties.OssAliyunConfigProperties;
import com.itheima.sfbx.file.pojo.FilePart;
import com.itheima.sfbx.file.service.IFilePartService;
import com.itheima.sfbx.file.service.IFileService;
import com.itheima.sfbx.framework.commons.basic.ResponseResult;
import com.itheima.sfbx.framework.commons.dto.file.FileVO;
import com.itheima.sfbx.framework.commons.dto.file.FilePartVO;
import com.itheima.sfbx.framework.commons.dto.file.UploadMultipartFile;
import com.itheima.sfbx.framework.commons.utils.ResponseResultBuild;
import com.itheima.sfbx.framework.commons.utils.SubjectContent;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName FileUpLoadController.java
 * @Description 文件上传接口
 */
@RestController
@RequestMapping("/file")
@Api(tags = "附件controller")
@Slf4j
public class FileUpLoadController {

    @Autowired
    IFileService fileService;
    @Autowired
    OssAliyunConfigProperties ossAliyunConfigProperties;

    /***
     * @description 文件上传-简单上传-前端直接调用
     * @param file 上传对象
     * @return: com.itheima.travel.req.FileVO
     */
    @PostMapping(value = "up-load")
    @ApiOperation(value = "文件上传-简单上传",notes = "文件上传-简单上传")
    @ApiImplicitParams({
        @ApiImplicitParam(paramType = "form", name = "file", value = "文件对象", required = true, dataTypeClass = MultipartFile.class)
    })
    @ApiOperationSupport(includeParameters = {"fileVO.businessType","fileVO.bucketName","fileVO.storeFlag","fileVO.autoCatalog"})
    public ResponseResult<FileVO> upLoad(
            @RequestParam("file") MultipartFile file,
            FileVO fileVO) throws IOException {
        //根据当前登录用户的信息获取 当前登录的用户 公司编号；
        fileVO.setCompanyNo(SubjectContent.getCompanyNo());

        //因为前端传死了桶名称，不是我们动态配置的；所以替换一下桶名称；我们系统桶名称来自nacos的配置
        fileVO.setBucketName(ossAliyunConfigProperties.getBucketName());

        //构建文件上传对象
        UploadMultipartFile uploadMultipartFile = UploadMultipartFile
            .builder()
                //原始文件名称
            .originalFilename(file.getOriginalFilename())
                //文件字节数组
            .fileByte(IOUtils.toByteArray(file.getInputStream()))
            .build();
        //执行文件上传
        FileVO fileVOResult = fileService.upLoad(uploadMultipartFile, fileVO);
        return ResponseResultBuild.successBuild(fileVOResult);

    }

    @Autowired
    private IFilePartService filePartService;

    @PostMapping("/list-uploaded-parts")
    @ApiOperation("查询某次上传会话中已上传的分片编号")
    public ResponseResult<Set<Integer>> listUploadedParts(
            @RequestBody FilePartVO filePartVO) {
        try{
            String uploadId = filePartVO.getUploadId();
            String companyNo = SubjectContent.getCompanyNo();

            List<FilePart> parts = filePartService.lambdaQuery()
                    .select(FilePart::getPartNumber)
                    .eq(FilePart::getUploadId,uploadId)
                    .eq(FilePart::getCompanyNo,companyNo)
                    .list();

            Set<Integer> uploadedPartNumbers = parts.stream()
                    .map(FilePart::getPartNumber)
                    .collect(Collectors.toSet());

            return ResponseResultBuild.successBuild(uploadedPartNumbers);
        } catch (Exception e) {
            log.error("查询已上传分片失败", e);
            //手动构建ResponseResult<Set<Integer>> 确保泛型一致
            ResponseResult<Set<Integer>> result = new ResponseResult<>();
            result.setCode(500);
            result.setMsg("查询失败");
            result.setData(null);
            return result;
        }
    }

    @PostMapping(value = "initiate-multipart-up-load")
    @ApiOperation(value = "文件分片上传-初始化",notes = "文件分片上传-初始化")
    @ApiImplicitParam(name = "fileVO",value = "文件对象",required = true,dataType = "FileVO")
    public ResponseResult<FileVO> initiateMultipartUpload(
            @RequestBody FileVO fileVO){
        //因为前端传死了桶名称，不是我们动态配置的；所以替换一下桶名称；我们系统桶名称来自nacos的配置
        fileVO.setBucketName(ossAliyunConfigProperties.getBucketName());
        fileVO.setCompanyNo(SubjectContent.getCompanyNo());
        //初始化上传Id
        FileVO fileVOResult = fileService.initiateMultipartUpload(fileVO);
        return ResponseResultBuild.successBuild(fileVOResult);
    }

    @PostMapping(value = "up-load-part")
    @ApiOperation(value = "文件分片上传-上传分片",notes = "文件分片上传-上传分片")
    @ApiImplicitParams({
        @ApiImplicitParam(paramType = "form", name = "file", value = "文件对象", required = true, dataTypeClass = MultipartFile.class)
    })
    public ResponseResult<String> uploadPart(
            @RequestParam("file") MultipartFile file,
            FilePartVO filePartVO)throws IOException {
        //因为前端传死了桶名称，不是我们动态配置的；所以替换一下桶名称；我们系统桶名称来自nacos的配置
        filePartVO.setBucketName(ossAliyunConfigProperties.getBucketName());

        filePartVO.setCompanyNo(SubjectContent.getCompanyNo());
        //构建文件上传对象
        UploadMultipartFile uploadMultipartFile = UploadMultipartFile
            .builder()
            .originalFilename(file.getOriginalFilename())
            .fileByte(IOUtils.toByteArray(file.getInputStream()))
            .build();
        //上传分片返回partETagJson
        String partETagJson = fileService.uploadPart(uploadMultipartFile,filePartVO);
        return ResponseResultBuild.successBuild(partETagJson);
    }

    @PostMapping(value = "complete-multipart-up-load")
    @ApiOperation(value = "文件分片上传-合并分片",notes = "文件分片上传-合并分片")
    @ApiImplicitParam(name = "fileVO",value = "文件对象",required = true,dataType = "FileVO")
    public ResponseResult<String> completeMultipartUpload(
            @RequestBody FileVO fileVO)throws IOException {
        //因为前端传死了桶名称，不是我们动态配置的；所以替换一下桶名称；我们系统桶名称来自nacos的配置
        fileVO.setBucketName(ossAliyunConfigProperties.getBucketName());
        //问上传分片返回partETagJson
        String eTagJson = fileService.completeMultipartUpload(fileVO);
        return ResponseResultBuild.successBuild(eTagJson);
    }

}
